第十章 信号
10.1 Linux信号概述
Linux下, 一个进程给其他进程发送信号的API是kill函数
1 |
|
信号处理方式
目标进程在收到信号时, 需要定义一个接收函数来处理.
1 | typedef void(*__sighandler_t) (int); // 定义一个函数名 |
该函数只有一个整型参数, 表示信号类型.
bits/signum.h头文件中还定义了i新年好的两种其他处理方式. SIG_IGN表示忽略目标信号, SIG_DFL表示使用信号的默认处理方式.
1 |
Linux信号
默认处理方式:
- 结束进程-Term
- 忽略信号-Ign
- 结束进程并生成核心转储文件-Core
- 暂停进程-Stop
- 继续进程-Cont
Linux的可用信号都定义在bits/signum.h中.
与网络编程紧密相关的又SIGHUP, SIGPIPE, SIGURG.
中断系统调用
程序在执行处于阻塞状态的系统调用时收到信号, 并且设置了信号处理函数, 则默认情况下系统调用会被中断, 且errno为EINTR. 可以使用sigaction函数为信号设置SA_RESTART标志以自动重启被中断的系统调用.
10.2 信号函数
1 |
|
- sig指定捕获的信号类型;_handler参数是_sighandler_t类型的函数指针, 指定信号sig的处理函数
1 | int sigaction(int sig, const struct sigaction* act, struct sigaction* oact); |
sigaction系统调用是更健壮(?)的接口.
- act指定新的信号处理方式; oact输出信号先前的处理方式.
- sigaction结构体中, sa_handler成员指定信号处理函数; sa_mask设置进程的信号掩码; sa_flags设置程序收到信号时的行为
10.3 信号集
Linux用数据结构sigset_t来表示一组信号, 其实际上时一个长整型数组, 数组的每个元素的每个位表示一个信号.
1 |
|
Linux提供了一组简化位运算的函数:
进程信号掩码
信号掩码可以指定哪些信号不能发送给本进程.
1 |
|
被挂起的信号
信号掩码会导致被屏蔽的信号不能被进程接收, OS会将这些信号设置为进程的一个被挂起的信号. 如果我们取消对被挂起信号的屏蔽, 则它能立即被进程收到, 如下函数能够获得进程当前被挂起的信号集
1 | int sigpending(sigset_t* set); |
10.4 统一事件源
信号是一种异步事件:信号处理函数和程序的主循环是两条不同的执行路线。很显然,信号处理函数需要尽可能快地执行完毕,以确保该信号不被屏蔽(前面提到过,为了避免
一些竞态条件,信号在处理期间,系统不会再次触发它)太久。一种典型的解决方案是:
把信号的主要处理逻辑放到程序的主循环中,当信号处理函数被触发时,它只是简单地通
知主循环程序接收到信号,并把信号值传递给主循环,主循环再根据接收到的信号值执行
目标信号对应的逻辑代码。信号处理函数通常使用管道来将信号“传递”给主循环:信号
处理函数往管道的写端写入信号值,主循环则从管道的读端读出该信号值。那么主循环怎
么知道管道上何时有数据可读呢?这很简单,我们只需要使用/O复用系统调用来监听管
道的读端文件描述符上的可读事件。如此一来,信号事件就能和其他I/O事件一样被处理,
即统一事件源。
10.5 网络编程相关信号
SIGHUP
当挂起进程的控制终端时,SIGHUP信号将被触发。对于没有控制终端的网络后台程序而言,它们通常利用SIGHUP信号来强制服务器重读配置文件。
SIGPIPE
默认情况下,往一个读端关闭的管道或socket连接中写数据将引发SIGPIPE信号。我们需要在代码中捕获并处理该信号,或者至少忽略它,因为程序接收到SIGPIPE信号的默认行为是结束进程,而我们绝对不希望因为错误的写操作而导致程序退出。引起SIGPIPE信号的写操作将设置errno为EPIPE。
SIGURG
SIGURG信号是内核通知应用程序带外数据到达的两种方式之一(另一种是处理socket系统调用的异常事件)
- Title: 第十章 信号
- Author: Huan Lee
- Created at : 2023-08-20 08:08:10
- Updated at : 2024-02-26 04:53:15
- Link: https://www.mirthfullee.com/2023/08/20/notion-第十章 信号-b2fb3ea2/
- License: This work is licensed under CC BY-NC-SA 4.0.